﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ServiceLocation;
using System.Globalization;
using System.Linq.Expressions;
using System.ComponentModel.Composition;

namespace SkeletonNET.Localization
{
    /// <summary>
    /// Class to do localization
    /// </summary>
    public class Localizer
    {
        private static IEnumerable<ILocalizer> Localizers { get; set; }
        private static Localizer Current { get; set; }

        [ImportingConstructor]
        public Localizer(IEnumerable<ILocalizer> localizers)
        {
            Localizers = localizers;
        }

        static Localizer()
        {
            Current = ServiceLocator.Current.GetInstance<Localizer>();
        }

        /// <summary>
        /// Localizes the specified key - culture combination.
        /// </summary>
        /// <param name="key">The key to search for.</param>
        /// <param name="culture">The culture to use. null will use the CurrentUiCulture</param>
        /// <returns>The translated string or !!<KEY>!! to indicate that no translation could be found</returns>
        public static string Localize(string key, CultureInfo culture = null)
        {
            if (culture == null)
                culture = CultureInfo.CurrentUICulture;

            string result = string.Empty;

            foreach (var localizer in Localizers)
            {
                result = localizer.Localize(key, culture);
                if (!string.IsNullOrEmpty(result))
                    break;
            }
            
            return result ?? "!!" + key + "!!";
        }

        /// <summary>
        /// Localizes the specified expression.
        /// The expression should point to a property which is decoarated with the LocalizeAttribute
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">The expression.</param>
        /// <returns></returns>
        public static string Localize<T>(Expression<Func<T, object>> expression)
        {
            var memberExpression = expression.Body as MemberExpression;
            var attributes = memberExpression.Member.GetCustomAttributes(typeof(LocalizeAttribute), true).Cast<LocalizeAttribute>();
            if (attributes.Count() > 0)
                return Localize(attributes.First().Key);

            return string.Empty;
        }

        /// <summary>
        /// Add a translation to a localizer.
        /// For now this is only here for testing purposes but we will see what's going to happen with it.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cultureInfo">The culture info.</param>
        /// <param name="key">The key to search for.</param>
        /// <param name="translation">The translation to add.</param>
        /// <returns>A reference to the requested localizer</returns>
        public static ILocalizer Get<T>()
            where T : ILocalizer
        {
            // Search for the requested localizer
            ILocalizer localizer = Localizers.OfType<T>().FirstOrDefault();
            if (localizer == null)
                throw new Exception(string.Format("Localizer of type {0} not found", typeof(T).FullName));

            return localizer;
        }
    }

    [InheritedExport]
    public interface ILocalizer
    {
        /// <summary>
        /// Localizes the specified input string.
        /// </summary>
        /// <param name="key">The input string.</param>
        /// <param name="culture">The culture.</param>
        /// <returns></returns>
        string Localize(string key, CultureInfo culture);
        /// <summary>
        /// Adds the translation to the localizer.
        /// </summary>
        /// <param name="culture">The culture.</param>
        /// <param name="identifier">The identifier.</param>
        /// <param name="translation">The translation.</param>
        /// <returns></returns>
        ILocalizer AddTranslation(CultureInfo culture, string identifier, string translation);
    }

    /// <summary>
    /// Attribute to localize properties
    /// </summary>
    public class LocalizeAttribute : Attribute
    {
        /// <summary>
        /// Gets or sets the key used to lookup the translation.
        /// </summary>
        /// <value>
        /// The key.
        /// </value>
        public string Key { get; set; }

        public LocalizeAttribute(string key)
        {
            Key = key;
        }
    }
}
